package mrpheu.demo.server.implement;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import mrpheu.demo.basic.interfaces.IMrPheuOPC;
import mrpheu.demo.server.classes.MrPheuBasicServer;
import mrpheu.demo.server.classes.ThreadPoolChat;
import mrpheu.demo.server.interfaces.IZoneClient;

public class MrPheuUDPServer extends MrPheuBasicServer implements Runnable, IMrPheuOPC {
    private Logger logger = Logger.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());
    
    private DatagramSocket server = null;
    @SuppressWarnings("unused")
    private ThreadPoolChat threadPoolClient;
    @SuppressWarnings("unused")
    private ThreadPoolChat threadPoolTimer;
    
    private BlockingQueue<Runnable> waitQueueClient = new LinkedBlockingQueue<>(200);
    private BlockingQueue<Runnable> waitQueueTimer = new LinkedBlockingQueue<>(200);
    
    public MrPheuUDPServer(int port, Map<Integer, IZoneClient> clientList, ThreadPoolChat threadPool) {
        super(port, clientList, threadPool);
        this.threadPoolClient = new ThreadPoolChat(100, 100, 10, TimeUnit.SECONDS, waitQueueClient);
        this.threadPoolTimer = new ThreadPoolChat(100, 100, 10, TimeUnit.SECONDS, waitQueueTimer);
    }
    
    @Override
    public boolean open() {
        this.logger.log(Level.WARNING, "UDPServer starting...");
           try {
               System.out.println(super.port);
            this.server = new DatagramSocket(super.port);
        } catch (SocketException e) {
            this.logger.log(Level.WARNING, "UDPServer's not start.");
            return false;
        }
        this.logger.log(Level.WARNING, "UDPServer started in port " + this.server.getLocalPort());
        return true;
    }

    @Override
    public void process() {
        if (this.server != null) {
            byte[] buf = new byte[256];
            while (!super.offServer) {
                this.logger.log(Level.WARNING, "Waiting for client...");
                try {
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    this.server.receive(packet);
                    InetAddress address = packet.getAddress();
                    
                    int id = ThreadLocalRandom.current().nextInt();
                    this.logger.log(Level.WARNING, "ID: " + id);
                    
                    String portStr = new String(packet.getData());
                    
                    DatagramSocket socket = new DatagramSocket();
                    this.logger.log(Level.WARNING, "Client UDP " + address + " connected. Port local: " + socket.getLocalPort());
                    ProcessUDPClient client = new ProcessUDPClient(id, socket, packet, Integer.parseInt(portStr.trim()));
                    this.clientList.put(id, client);
                    this.threadPool.execute(client);
//                    byte[] dataByte = packet.getData();                  
//                    String line = new String(dataByte);
//                    String[] message = line.split(":");
//                    
//                    if(processData(message) == 1) { // message
//                        String standardStr = MrPheuUDPServer.joinReturnStandardStr(message);
//                        MessageItem messageItem = MessageItem.processData(standardStr);
//                        try {
//                            ServerChat.messageList.put(messageItem);
//                        } catch (InterruptedException e) {
//                            // TODO Auto-generated catch block
//                            e.printStackTrace();
//                        }
//                    } else { // connect
//                        ProcessUDPClient client = new ProcessUDPClient(id);
//                        this.clientList.put(id, client);
//                    }
                    
                } catch (IOException e1) {
                    this.logger.log(Level.WARNING, "Client fail.");
                }
            }
            this.close();
        }
    }
    
    public static String joinReturnStandardStr(String[] message) {
        String rs = "";
        int len = message.length;
        for(int i = 1; i < len; i++) {
            rs += message[i];
        }
        return rs;
    }
    
    /**
     * 
     * @param message
     * @return if kq = 0: connect, kq = 1: message
     */
    public int processData(String[] message) {
        if (message.length >= 1 && message[0].equals("1")) { // flag
            return 0;
        }
        return 1;
    }
    
    @Override
    public boolean close() {
        if(this.server != null) {
            this.server.close();
        }
        return true;
    }

    @Override
    public void run() {
        this.open();
        this.process();
        //this.close();
    }
    
}
